package com.sojson.util.file.system.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.ClassPathResource;

import com.sojson.constant.Constant;
import com.sojson.util.StringUtil;
import com.sojson.util.file.FileUtil;
import com.sojson.util.file.bean.UploadBean;
import com.sojson.util.file.system.FileSystemInterface;
import com.sojson.util.init.InitUtil;
import com.sojson.util.properties.PropertiesUtil;

import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;

/**
 * FastDFS文件系统工具类
 *
 * @author liu
 * @Date 2020-06-15 14:45:43
 * @Description
 *
 */
@Slf4j
public class FastDfsUtilImpl implements FileSystemInterface {

    private static FastDfsUtilImpl fastDFSUtilsImpl;
    private StorageServer storageServer = null;
    private TrackerServer trackerServer = null;
    private TrackerClient trackerClient = null;
    private StorageClient client = getClient();
    /** FastDFS的服务器的协议 */
    private final String AGREEMENT = Convert.toStr(Constant.PROPERTIES.getProperty("so.fastdfs.agreement"), "http://");
    /** FastDFS的服务器的地址 */
    private final String URL = Constant.PROPERTIES.getProperty("so.fastdfs.url");
    /** FastDFS的服务器加密的密钥 */
    private String secretKey =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.fastdfs.http_secret_key"), "SojsonFastDFSToken");

    private FastDfsUtilImpl() {}

    @Override
    protected void finalize() throws Throwable {
        close();
    }

    /**
     * 文件上传
     *
     * @param filePath  文件位置
     * @param dir       上传目录
     * @return
     * @throws Exception
     */
    @Override
    public UploadBean upload(String filePath, String dir) throws Exception {
        return upload(FileUtil.readByes(filePath), dir, FileUtil.getFileSuffix(filePath));
    }

    /**
     * 文件上传
     *
     * @param fileStream    文件流
     * @param dir           上传目录
     * @param fileName      文件名
     * @return
     * @throws Exception
     */
    @Override
    public UploadBean upload(InputStream fileStream, String dir, String fileSuffix) throws Exception {
        return upload(FileUtil.readByes(fileStream), dir, fileSuffix);
    }

    /**
     * 文件上传
     *
     * @param fileBytes     文件字节流
     * @param dir           上传目录
     * @param fileSuffix    文件后缀
     * @return
     * @throws Exception
     */
    @Override
    public UploadBean upload(byte[] fileBytes, String dir, String fileSuffix) throws Exception {
        String[] fileIds = null;
        fileIds = client.upload_file(BUCKET_NAME + dir, fileBytes, fileSuffix, null);
        // System.out.println(fileIds.length);
        // System.out.println("组名:" + fileIds[0]);
        // System.out.println("路径: " + fileIds[1]);

        UploadBean upload = new UploadBean();
        upload.setObjectName(fileIds[1]);
        return upload;
    }

    /**
     * 下载文件
     *
     * @param objectName    唯一标识
     * @param dir           文件路径
     * @param fileName      文件名
     * @return
     * @throws Exception
     */
    @Override
    public boolean download(String objectName, String dir, String fileName) throws Exception {
        return client.download_file(BUCKET_NAME, objectName,
            new StringBuilder(FileUtil.THIS_LOCALITY_DIRECTORY_BUCKET_NAME_BASE).append("/").append(dir).append("/")
                .append(fileName).toString()) == 0;
    }

    /**
     * 下载文件
     *
     * @param objectName    唯一标识
     * @return
     * @throws Exception
     */
    @Override
    public InputStream downloadGetStream(String objectName) throws Exception {
        return FileUtil.readInputStream(downloadGetBytes(objectName));
    }

    /**
     * 下载文件
     *
     * @param objectName    唯一标识
     * @return
     * @throws Exception
     */
    @Override
    public byte[] downloadGetBytes(String objectName) throws Exception {
        return client.download_file(BUCKET_NAME, objectName);
    }

    /**
     * 删除文件
     *
     * @param objectName    唯一标识
     * @return
     * @throws Exception
     */
    @Override
    public boolean remove(String objectName) throws Exception {
        return client.delete_file(BUCKET_NAME, objectName) == 0;
    }

    /**
     * 获取文件路径
     *
     * @param objectName    唯一标识
     * @return
     * @throws Exception
     */
    @Override
    public String getUrl(String objectName) throws Exception {
        StringBuilder sb = new StringBuilder(AGREEMENT);
        sb.append(URL);
        sb.append("/");
        sb.append(BUCKET_NAME);
        sb.append("/");
        sb.append(objectName);
        return sb.toString();
    }

    /**
     * 获取文件路径(临时路径)
     *
     * @param objectName    唯一标识
     * @return
     * @throws Exception
     */
    @Override
    public String getUrlTemporary(String objectName) throws Exception {
        return getUrlTemporary(objectName, FILE_TIMEOUT);
    }

    /**
     * 获取文件路径(临时路径)
     *
     * @param objectName    唯一标识
     * @param timeout       超时时间(单位: 秒)
     * @return
     * @throws Exception
     */
    @Override
    public String getUrlTemporary(String objectName, int timeout) throws Exception {
        StringBuilder sb = new StringBuilder(AGREEMENT);
        sb.append(URL);
        sb.append("/");
        sb.append(BUCKET_NAME);
        sb.append("/");
        sb.append(objectName);
        sb.append("?");
        sb.append("token=").append(ProtoCommon.getToken(objectName, timeout, secretKey));
        sb.append("&ts=").append(timeout);
        return sb.toString();
    }

    /**
     * 关闭连接
     *
     * @param conn
     * @throws IOException
     */
    void close() throws IOException {
        log.info("正在关闭FastDFS");
        if (StringUtil.isNotBlankObject(storageServer)) {
            try {
                storageServer.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        if (StringUtil.isNotBlankObject(trackerServer)) {
            try {
                trackerServer.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    private StorageClient getClient() {
        try {
            // 用main方法的时候调用
            // ClientGlobal.init("environment/constant/fdfs-client.properties");
            // 用容器的时候调用
            String property = Constant.PROPERTIES.getProperty("so.filename.fdfsClient");
            if (StringUtil.isBlankString(property)) {
                log.warn("FastDFS初始化异常,fdfs-client.properties不存在!");
                return null;
            }
            property = InitUtil.URL_BASE + property;
            ClassPathResource classPathResource = new ClassPathResource(property);
            if (!classPathResource.exists()) {
                log.warn("FastDFS初始化异常,fdfs-client.properties不存在!");
                return null;
            }
            Properties properties = PropertiesUtil.getProperties(classPathResource);
            ClientGlobal.initByProperties(properties);
            trackerClient = new TrackerClient();
            trackerServer = trackerClient.getConnection();
            return new StorageClient(trackerServer, storageServer);
        } catch (Exception e) {
            log.error("FastDFS初始化异常," + e.getMessage());
        }
        return null;
    }

    public static FastDfsUtilImpl getInstances() {
        if (StringUtil.isBlankObject(fastDFSUtilsImpl)) {
            fastDFSUtilsImpl = new FastDfsUtilImpl();
        }
        return fastDFSUtilsImpl;
    }

}